#include <stdio.h>

#include <inject.h>
#include <envs.h>

#include <launcher_p.h>

const wchar_t *LAUNCHER_INJECT_DLL = L"launcher_payload.dll";
const wchar_t *GAME_INJECT_DLL = L"game_payload.dll";

#define SHIFT(argc, argv) (argc--, *argv++)

int wmain(int argc, wchar_t **argv) {
    // Read arguments
    wchar_t *game_path = NULL;
    wchar_t *launcher_path = NULL;

    // Skip executable
    SHIFT(argc, argv);
    
    switch (argc) {
        case 0:
            wprintf(L"Usage: wine jadeite.exe [game path] <launcher path>\n");
            return 0;
        case 1:
            game_path = SHIFT(argc, argv);
            launcher_path = L"--";
            break;
        default:
            game_path = SHIFT(argc, argv);
            launcher_path = SHIFT(argc, argv);
            break;
    }

    // Default launcher path
    if (wcscmp(launcher_path, L"--") == 0) {
        wprintf(L"No launcher process specified! Using explorer.exe\n");
        launcher_path = L"C:\\Windows\\explorer.exe";
    } 

    // Compute absolute arg path
    wchar_t game_exe_path[MAX_PATH];
    GetFullPathNameW(game_path, MAX_PATH, game_exe_path, NULL);

    // cd into the injector directory
    wchar_t injector_path[MAX_PATH];
    GetModuleFileNameW(GetModuleHandleW(NULL), injector_path, MAX_PATH);

    *(wcsrchr(injector_path, L'\\')) = L'\0';
    
    SetCurrentDirectoryW(injector_path);

    // Compute absolute dll paths
    wchar_t game_payload_path[MAX_PATH];
    GetFullPathNameW(GAME_INJECT_DLL, MAX_PATH, game_payload_path, NULL);

    wchar_t launcher_payload_path[MAX_PATH];
    GetFullPathNameW(LAUNCHER_INJECT_DLL, MAX_PATH, launcher_payload_path, NULL);

    // Verify that the DLLs exist
    if (GetFileAttributesW(game_payload_path) == INVALID_FILE_ATTRIBUTES) {
        wprintf(L"Cannot find game_payload.dll! Make sure that you extracted the entire jadeite release archive\n");
        return 1;
    }

    if (GetFileAttributesW(launcher_payload_path) == INVALID_FILE_ATTRIBUTES) {
        wprintf(L"Cannot find launcher_payload.dll! Make sure that you extracted the entire jadeite release archive\n");
        return 1;
    }

    // Construct commandline for the game process
    wchar_t cmdline[8192];
    wsprintfW(cmdline, L"\"%ls\"", game_exe_path);

    while (argc) {
        wchar_t arg[8192];
        wsprintfW(arg, L" \"%ls\"", SHIFT(argc, argv));
        wcscat(cmdline, arg);
    }

    // Set envvars
    SetEnvironmentVariableW(ENV_EXE_PATH, game_exe_path);
    SetEnvironmentVariableW(ENV_DLL_PATH, game_payload_path);
    SetEnvironmentVariableW(ENV_PROC_CMD, cmdline);

    // Start the launcher
    wprintf(L"Starting '%ls' via '%ls'\n", game_exe_path, launcher_path);

    STARTUPINFOW si;
    ZeroMemory(&si, sizeof(si));
    si.cb = sizeof(si);

    PROCESS_INFORMATION pi;
    ZeroMemory(&pi, sizeof(pi));

    if (!CreateProcessW(
        launcher_path,
        NULL,
        NULL,
        NULL,
        FALSE,
        CREATE_SUSPENDED,
        NULL,
        NULL,
        &si,
        &pi
    )) {
        fwprintf(stderr, L"Could not start process! (%ld)\n", GetLastError());
        exit(1);
    }

    wprintf(L"Started launcher process (%ld)\n", pi.dwProcessId);

    // Inject
    void *payload_start = &_binary_launcher_p_o_p_launcher_p_bin_start;
    size_t payload_size = (size_t)&_binary_launcher_p_o_p_launcher_p_bin_size; // yes this is valid
    inject(pi.hProcess, payload_start, payload_size, launcher_payload_path);

    // Resume the process
    ResumeThread(pi.hThread);

    return 0;
}
